package org.runtimedao.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import org.apache.log4j.Logger;
import org.runtimedao.exception.DAOException;

public class DAOHelper {

	public static final String DEFAULT_PERSISTENCE_UNIT_NAME = "runtimeDAO";
	private static final String NO_PERSISTENCE_UNIT_LOADED = "No persistence unit loaded";

	private static EntityManagerFactory factory;
	private static ThreadLocal<EntityManager> session = new ThreadLocal<EntityManager>();

	private static final Logger LOG = Logger.getLogger(DAOHelper.class);

	/**
	 * 
	 * @param persistenceUnit
	 */
	public static synchronized void loadPersistenceUnit(String persistenceUnit) {
		closeFactory();
		LOG.info("Loading persistence unit: " + persistenceUnit);
		factory = Persistence.createEntityManagerFactory(persistenceUnit);
	}

	/**
	 * Creates or return an entity manager
	 * 
	 * @return
	 */
	public static synchronized EntityManager getEntityManager() {
		EntityManager em = session.get();
		if (em == null) {
			if (factory == null) {
				LOG.error(NO_PERSISTENCE_UNIT_LOADED);
				throw new DAOException(NO_PERSISTENCE_UNIT_LOADED);
			}

			LOG.info("Creating entity manager");
			em = factory.createEntityManager();
			session.set(em);
		}

		return em;
	}

	/**
	 * Clean up entity manager
	 */
	public static synchronized void cleanUp() {
		EntityManager em = getEntityManager();
		if (em != null) {
			LOG.debug("Cleaning up");
			if (em.isOpen()) {
				em.close();
			}
			session.set(null);
		}
	}

	public static synchronized boolean isPersistenceUnitLoaded() {
		if (factory == null) {
			return false;
		}
		return true;
	}

	/**
	 * Close entity manager factory
	 */
	public static synchronized void closeFactory() {
		if (factory != null) {
			LOG.info("Closing entity manager factory");
			if (factory.isOpen()) {
				factory.close();
			}
			factory = null;
			DAOCache.resetCache();
		}
	}

	/**
	 * Begins a transaction if it is not active
	 * 
	 * @param em
	 */
	public static void beginTransaction() {
		EntityManager em = getEntityManager();
		EntityTransaction transaction = em.getTransaction();
		if (!transaction.isActive()) {
			LOG.debug("Beginning transaction");
			transaction.begin();
		}
	}

	/**
	 * Commits if transaction is not active
	 * 
	 * @param em
	 */
	public static void commit() {
		EntityManager em = getEntityManager();
		EntityTransaction transaction = em.getTransaction();
		if (transaction.isActive()) {
			LOG.debug("Commiting");
			transaction.commit();
		}
	}

	/**
	 * Rollback if transaction is active
	 * 
	 * @param em
	 */
	public static void rollback() {
		EntityManager em = getEntityManager();
		EntityTransaction transaction = em.getTransaction();
		if (transaction.isActive()) {
			LOG.debug("Rollbacking");
			transaction.rollback();
		}
	}
}
